Imports System.Collections.Generic
Imports System.IO
Imports System.Configuration
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Graphics
Imports Microsoft.Xna.Framework.Input
Imports Microsoft.Xna.Framework.Input.Touch
Imports Microsoft.Xna.Framework.Content
Imports Microsoft.Xna.Framework.Audio
Imports Microsoft.Xna.Framework.Media




''' <summary>
''' This is the main type for your game
''' </summary>
Public Class PrinceOfPersiaGame
	Inherits GameScreen

	'private Texture2D[] playerTexture = new Texture2D[128];

	' Resources for drawing.
	'private GraphicsDeviceManager graphics;
	'private SpriteBatch spriteBatch;

	' Global content.
	'[ContentSerializerIgnore] 
	'List<Sequence> l ;
	'[ContentSerializerIgnore] 
	Private hudFont As SpriteFont
	'[ContentSerializerIgnore]
	Private PoPFont As SpriteFont
	'[ContentSerializerIgnore] 

	Public Shared player_livePoints As Texture2D
	Public Shared player_energy As Texture2D

	Public Shared enemy_livePoints As Texture2D
	Public Shared enemy_energy As Texture2D

	'public static Texture2D player_splash;
	'public static Texture2D enemy_splash;

	' Meta-level game state.
	Private levels As Level() = New Level(29) {}
	'private int levelIndex = 0;
	Private wasContinuePressed As Boolean
	Private maze As Maze


	' When the time remaining is less than the warning time, it blinks on the hud
	Private Shared ReadOnly WarningTime As TimeSpan = TimeSpan.FromSeconds(30)

	' We store our input states so that we only poll once per frame, 
	' then we use the same input state wherever needed
	Private gamePadState As GamePadState
	Private keyboardState As KeyboardState
	Private touchState As TouchCollection
	Private accelerometerState As AccelerometerState

	' The number of levels in the Levels directory of our content. We assume that
	' levels in our content are 0-based and that all numbers under this constant
	' have a level file present. This allows us to not need to check for the file
	' or handle exceptions, both of which can add unnecessary time to level loading.
	Private Const numberOfLevels As Integer = 3

	Public Shared CONFIG_DEBUG As Boolean = False
	Public Shared CONFIG_FRAMERATE As Single = 0.09F
	Public Shared CONFIG_SPRITE_KID As String
	Public Shared CONFIG_SPRITE_GUARD As String
	Public Shared CONFIG_SPRITE_EFFECTS As String
	Public Shared CONFIG_SONGS As String
	Public Shared CONFIG_SOUNDS As String
	Public Shared CONFIG_TILES As String
	Public Shared CONFIG_ITEMS As String



	Public Shared CONFIG_PATH_CONTENT As String = System.AppDomain.CurrentDomain.BaseDirectory + "Content\"
	Public Shared CONFIG_PATH_APOPLEXY As String = "Apoplexy\"
	Public Shared CONFIG_PATH_LEVELS As String = "Levels\"
	Public Shared CONFIG_PATH_ROOMS As String = "Rooms\"
	Public Shared CONFIG_PATH_SEQUENCES As String = "Sequences\"

	Public Shared CONFIG_KID_START_ENERGY As Integer = 3





	Private content As ContentManager

	Public ReadOnly Property spriteBatch() As SpriteBatch
		Get
			Return MyBase.ScreenManager.SpriteBatch
		End Get
	End Property

	Public ReadOnly Property GraphicsDevice() As GraphicsDevice
		Get
			Return MyBase.ScreenManager.GraphicsDevice
		End Get
	End Property





	Public Sub New()

		#If ANDROID Then
		CONFIG_PATH_CONTENT = System.AppDomain.CurrentDomain.BaseDirectory & "Content/"
		CONFIG_PATH_LEVELS = "Levels/"
		CONFIG_PATH_ROOMS = "Rooms/"
		CONFIG_PATH_SEQUENCES = "Sequences/"
		#End If

		#If WINDOWS Then
		'READ APP.CONFIG for configuration settings
		Boolean.TryParse(System.Configuration.ConfigurationManager.AppSettings("CONFIG_debug"), CONFIG_DEBUG)
		Single.TryParse(System.Configuration.ConfigurationManager.AppSettings("CONFIG_framerate"), CONFIG_FRAMERATE)

		'READ CONTENT RESOURCES PATH
		CONFIG_SPRITE_KID = System.Configuration.ConfigurationManager.AppSettings("CONFIG_sprite_kid").ToString().ToUpper()
		CONFIG_SPRITE_GUARD = System.Configuration.ConfigurationManager.AppSettings("CONFIG_sprite_guard").ToString().ToUpper()
		CONFIG_SOUNDS = System.Configuration.ConfigurationManager.AppSettings("CONFIG_sound").ToString().ToUpper()
		CONFIG_SONGS = System.Configuration.ConfigurationManager.AppSettings("CONFIG_songs").ToString().ToUpper()
		CONFIG_TILES = System.Configuration.ConfigurationManager.AppSettings("CONFIG_tiles").ToString().ToUpper()
		CONFIG_ITEMS = System.Configuration.ConfigurationManager.AppSettings("CONFIG_items").ToString().ToUpper()
		CONFIG_PATH_SEQUENCES = System.Configuration.ConfigurationManager.AppSettings("CONFIG_path_Sequences").ToString().ToUpper()
		CONFIG_SPRITE_EFFECTS = System.Configuration.ConfigurationManager.AppSettings("CONFIG_sprite_effects").ToString().ToUpper()


		CONFIG_KID_START_ENERGY = Integer.Parse(System.Configuration.ConfigurationManager.AppSettings("CONFIG_kid_start_energy").ToString())

		CONFIG_PATH_CONTENT = "Content/"
		#End If
		AnimationSequence.frameRate = CONFIG_FRAMERATE


		Accelerometer.Initialize()
	End Sub



	''' <summary>
	''' Load graphics content for the game.
	''' </summary>
	Public Overrides Sub Activate(instancePreserved As Boolean)
		If Not instancePreserved Then
			If content Is Nothing Then
				content = ScreenManager.content
			End If
			'content = new ContentManager(ScreenManager.Game.Services, CONFIG_PATH_CONTENT);

			LoadContent()

			'LOAD MAZE
			maze = New Maze(GraphicsDevice, content)
			'NOW START
			maze.StartRoom().StartNewLife(ScreenManager.GraphicsDevice)

			' once the load has finished, we use ResetElapsedTime to tell the game's
			' timing mechanism that we have just finished a very long frame, and that
			' it should not try to catch up.
			ScreenManager.Game.ResetElapsedTime()
		End If

	End Sub


	Public Overrides Sub Deactivate()
		MyBase.Deactivate()
	End Sub


	''' <summary>
	''' Unload graphics content used by the game.
	''' </summary>
	Public Overrides Sub Unload()
		content.Unload()

	End Sub

	''' <summary>
	''' LoadContent will be called once per game and is the place to load
	''' all of your content.
	''' </summary>
	Protected Sub LoadContent()

		' Load fonts
		hudFont = content.Load(Of SpriteFont)("Fonts/Hud")
		PoPFont = content.Load(Of SpriteFont)("Fonts/PoP")

		'energy...
		player_energy = content.Load(Of Texture2D)("Sprites/bottom/player_live_full")
		player_livePoints = content.Load(Of Texture2D)("Sprites/bottom/player_live_empty")
		enemy_energy = content.Load(Of Texture2D)("Sprites/bottom/enemy_live_full")
		enemy_livePoints = content.Load(Of Texture2D)("Sprites/bottom/enemy_live_empty")

		'Splash
		'player_splash = content.Load<Texture2D>("Sprites/bottom/player_splash");
		'enemy_splash = content.Load<Texture2D>("Sprites/bottom/enemy_splash");



		'Known issue that you get exceptions if you use Media PLayer while connected to your PC
		'See http://social.msdn.microsoft.com/Forums/en/windowsphone7series/thread/c8a243d2-d360-46b1-96bd-62b1ef268c66
		'Which means its impossible to test this from VS.
		'So we have to catch the exception and throw it away
		'try
		'{
		'    MediaPlayer.IsRepeating = true;
		'    MediaPlayer.Play(content.Load<Song>("Sounds/dos/main theme"));
		'}
		'catch { }







	End Sub

	''' <summary>
	''' Allows the game to run logic such as updating the world,
	''' checking for collisions, gathering input, and playing audio.
	''' </summary>
	''' <param name="gameTime">Provides a snapshot of timing values.</param>
	Public Overrides Sub Update(gameTime As GameTime, otherScreenHasFocus As Boolean, coveredByOtherScreen As Boolean)
		HandleInput(gameTime, Nothing)

        For Each r As RoomNew In maze.rooms
            r.Update(gameTime, keyboardState, gamePadState, touchState, accelerometerState, Microsoft.Xna.Framework.DisplayOrientation.[Default])
        Next
		maze.player.Update(gameTime, keyboardState, gamePadState, touchState, accelerometerState, Microsoft.Xna.Framework.DisplayOrientation.[Default])




		'Other sprites update
		For Each s As Sprite In maze.player.SpriteRoom.SpritesInRoom()

			Select Case s.[GetType]().Name
				Case "Guard"
					If True Then
						DirectCast(s, Guard).Update(gameTime, keyboardState, gamePadState, touchState, accelerometerState, Microsoft.Xna.Framework.DisplayOrientation.[Default])
						Exit Select
					End If

				Case "Splash"
					If True Then
						DirectCast(s, Splash).Update(gameTime, keyboardState, gamePadState, touchState, accelerometerState, Microsoft.Xna.Framework.DisplayOrientation.[Default])
						Exit Select
					End If
				Case Else

					Exit Select
			End Select
			'delete object in state == delete
			If s.spriteState.Value().state = Enumeration.State.delete Then
					's.sprite.FrameIndex = 0;
				maze.sprites.Remove(s)
			End If
		Next


		MyBase.Update(gameTime, otherScreenHasFocus, False)
	End Sub

	Public Overrides Sub HandleInput(gameTime As GameTime, input As InputState)
		'''/ get all of our input states
		keyboardState = Keyboard.GetState()
		'gamePadState = GamePad.GetState(PlayerIndex.One);
		touchState = TouchPanel.GetState()
		accelerometerState = Accelerometer.GetState()

		If maze.player.IsAlive = False Then
            If keyboardState.IsKeyDown(Keys.Space) OrElse gamePadState.IsButtonDown(Buttons.A) OrElse touchState.Any = True Then
                maze.StartRoom().StartNewLife(ScreenManager.GraphicsDevice)
            End If
		End If

		' Exit the game when back is pressed.
		'''// if (gamePadState.Buttons.Back == ButtonState.Pressed)
		'''/// Exit();

        Dim continuePressed As Boolean = keyboardState.IsKeyDown(Keys.Space) OrElse gamePadState.IsButtonDown(Buttons.A) OrElse touchState.Any()


		wasContinuePressed = continuePressed
	End Sub



	''' <summary>
	''' Draws the game from background to foreground.
	''' </summary>
	''' <param name="gameTime">Provides a snapshot of timing values.</param>
    Public Overrides Sub Draw(gameTime As GameTime)
        'graphics.GraphicsDevice.Clear(Color.Black);

        '''/spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.NonPremultiplied);
        MyBase.ScreenManager.SpriteBatch.Begin()

        'base.ScreenManager.SpriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);


        maze.player.SpriteRoom.Draw(gameTime, spriteBatch)
        maze.player.Draw(gameTime, spriteBatch)


        'now drow sprites
        maze.player.SpriteRoom.DrawSprites(gameTime, spriteBatch)


        'now drow the mask
        maze.player.SpriteRoom.DrawMask(gameTime, spriteBatch)


        DrawBottom()
        DrawHud()


        'spriteBatch.End();

        MyBase.Draw(gameTime)

        MyBase.ScreenManager.SpriteBatch.[End]()
    End Sub

	Private Sub DrawBottom()
        Dim hudLocation As New Vector2(0, Game1.CONFIG_SCREEN_HEIGHT - RoomNew.BOTTOM_BORDER)

		'DRAW BLACK SQUARE
        Dim r As New Rectangle(0, 0, Game1.CONFIG_SCREEN_WIDTH, Game1.CONFIG_SCREEN_HEIGHT)
		Dim dummyTexture As New Texture2D(spriteBatch.GraphicsDevice, 1, 1)
		dummyTexture.SetData(New Color() {Color.Black})
		'Texture2D tx = new Texture2D(spriteBatch.GraphicsDevice, Game.CONFIG_SCREEN_WIDTH, Game.CONFIG_SCREEN_HEIGHT);
		'Texture2D tx = livePoints;
		spriteBatch.Draw(dummyTexture, hudLocation, r, Color.White)


		'check if death
        hudLocation = New Vector2(Game1.CONFIG_SCREEN_WIDTH \ 3, Game1.CONFIG_SCREEN_HEIGHT - RoomNew.BOTTOM_BORDER)
		If maze.player.IsAlive = False Then
			DrawShadowedString(PoPFont, "Press Space to Continue", hudLocation, Color.White)
		End If

		Dim source As New Rectangle(0, 0, player_livePoints.Width, player_livePoints.Height)

		Dim offset As Integer = 1
		Dim player_triangle As Texture2D = player_livePoints
		For x As Integer = 1 To maze.player.LivePoints
            hudLocation = New Vector2(0 + offset, Game1.CONFIG_SCREEN_HEIGHT - RoomNew.BOTTOM_BORDER)
			' Calculate the source rectangle of the current frame.


			If x <= maze.player.Energy Then
				player_triangle = player_energy
			Else
				player_triangle = player_livePoints
			End If

			' Draw the current tile.
			spriteBatch.Draw(player_triangle, hudLocation, source, Color.White, 0F, Vector2.Zero, _
				1F, SpriteEffects.None, 0)
			offset += player_livePoints.Width + 1
		Next


		'Draw opponent energy
		offset = 1
		For Each s As Sprite In maze.player.SpriteRoom.SpritesInRoom()
			Select Case s.[GetType]().Name
				Case "Guard"
					If True Then
						offset = enemy_livePoints.Width + 1
						Dim enemy_triangle As Texture2D = enemy_livePoints
						For x As Integer = 1 To maze.player.LivePoints
                            hudLocation = New Vector2(Game1.CONFIG_SCREEN_WIDTH - offset, Game1.CONFIG_SCREEN_HEIGHT - RoomNew.BOTTOM_BORDER)

							If x <= s.Energy Then
								enemy_triangle = enemy_energy
							Else
								enemy_triangle = enemy_livePoints
							End If

							' Draw the current tile.
							spriteBatch.Draw(enemy_triangle, hudLocation, source, Color.White, 0F, Vector2.Zero, _
								1F, SpriteEffects.None, 0)
							offset += enemy_livePoints.Width + 1
						Next
						Exit Select
					End If
				Case Else
					Exit Select

			End Select
		Next

		'DrawShadowedString(PoPFont, maze.PlayerRoom.roomName, hudLocation, Color.White);
	End Sub

	Private Sub DrawDebug(room As RoomNew)
		'if (room.player.sprite.sequence == null)
		'    return;

		Dim titleSafeArea As Rectangle = GraphicsDevice.Viewport.TitleSafeArea
		Dim hudLocation As New Vector2(titleSafeArea.X, titleSafeArea.Y)


		'END OF DEVELOPMENT???????
		If room.roomName = "MAP_dungeon_prison_9.xml" Then
			Dim sMessage As String = String.Empty
			sMessage = "Congratulations! Did you finish the first level of Prince of Persia.net!"
			DrawShadowedString(PoPFont, sMessage, hudLocation, Color.Yellow)
			hudLocation.Y = hudLocation.Y + 30

			sMessage = "Today 7 May of 2013,"
			DrawShadowedString(PoPFont, sMessage, hudLocation, Color.White)
			hudLocation.Y = hudLocation.Y + 30

			sMessage = "I ask for help to complete the development of this project!"
			DrawShadowedString(PoPFont, sMessage, hudLocation, Color.Red)
			hudLocation.Y = hudLocation.Y + 30

			sMessage = "It was my intention to complete all levels and complete the"
			DrawShadowedString(PoPFont, sMessage, hudLocation, Color.White)
			hudLocation.Y = hudLocation.Y + 30

			sMessage = "features that are missing, it would also be nice to bring this game on"
			DrawShadowedString(PoPFont, sMessage, hudLocation, Color.White)
			hudLocation.Y = hudLocation.Y + 30

			sMessage = "other device like : Linux, Android and Apple iOS."
			DrawShadowedString(PoPFont, sMessage, hudLocation, Color.White)
			hudLocation.Y = hudLocation.Y + 30

			sMessage = "Unfortunately for complete Prince of Persia.net and porting to other device"
			DrawShadowedString(PoPFont, sMessage, hudLocation, Color.White)
			hudLocation.Y = hudLocation.Y + 30

			sMessage = "I need your help to buy the kit developed by Xamarin ($ 999 business lic)"
			DrawShadowedString(PoPFont, sMessage, hudLocation, Color.White)
			hudLocation.Y = hudLocation.Y + 30

			sMessage = "So if you liked my work to make a donation, see on my blog at:"
			DrawShadowedString(PoPFont, sMessage, hudLocation, Color.White)
			hudLocation.Y = hudLocation.Y + 30

			sMessage = "http://princeofpersiadotnet.blogspot.it"
			DrawShadowedString(PoPFont, sMessage, hudLocation, Color.Yellow)
			hudLocation.Y = hudLocation.Y + 30

			sMessage = "http://www.falappi.it"
			DrawShadowedString(PoPFont, sMessage, hudLocation, Color.Yellow)
			hudLocation.Y = hudLocation.Y + 30


			Return
		End If


		If CONFIG_DEBUG = False Then
			Return
		End If


		DrawShadowedString(hudFont, "ROMM NAME=" & maze.player.SpriteRoom.roomName, hudLocation, Color.White)
		hudLocation.Y = hudLocation.Y + 10

		DrawShadowedString(hudFont, "POSTION X=" & maze.player.Position.X.ToString() & " Y=" & maze.player.Position.Y.ToString(), hudLocation, Color.White)
		hudLocation.Y = hudLocation.Y + 10
		DrawShadowedString(hudFont, "FRAME RATE=" & AnimationSequence.frameRate.ToString(), hudLocation, Color.White)

		hudLocation.Y = hudLocation.Y + 10
		DrawShadowedString(hudFont, "PLAYER STATE=" & Convert.ToString(maze.player.spriteState.Value().state) & " SEQUENCE CountOffset=" & Convert.ToString(maze.player.sprite.sequence.CountOffSet), hudLocation, Color.White)

		' Get the player's bounding rectangle and find neighboring tiles.
		Dim playerBounds As Rectangle = maze.player.Position.Bounding
		Dim v4 As Vector4 = room.getBoundTiles(playerBounds)

		' For each potentially colliding Tile, warning the for check only the player row ground..W
		For y As Integer = CInt(Math.Truncate(v4.Z)) To CInt(Math.Truncate(v4.W))
			For x As Integer = CInt(Math.Truncate(v4.X)) To CInt(Math.Truncate(v4.Y))
				Dim tileBounds As Rectangle = room.GetBounds(x, y)
				Dim depth As Vector2 = RectangleExtensions.GetIntersectionDepth(playerBounds, tileBounds)
				Dim tileCollision As Enumeration.TileCollision = room.GetCollision(x, y)
				Dim tileType As Enumeration.TileType = room.[GetType](x, y)

				hudLocation.Y = hudLocation.Y + 10
				DrawShadowedString(hudFont, "GRID X=" & x & " Y=" & y & " TILETYPE=" & tileType.ToString() & " BOUND X=" & tileBounds.X & " Y=" & tileBounds.Y & " DEPTH X=" & depth.X & " Y=" & depth.Y, hudLocation, Color.White)
			Next
		Next
	End Sub


	Private Sub DrawHud()
		'RoomNew room = maze.playerRoom;
		Dim titleSafeArea As Rectangle = GraphicsDevice.Viewport.TitleSafeArea
		Dim hudLocation As New Vector2(titleSafeArea.X, titleSafeArea.Y)
		Dim center As New Vector2(titleSafeArea.X + titleSafeArea.Width / 2F, titleSafeArea.Y + titleSafeArea.Height / 2F)

		' Draw score
		hudLocation.X = hudLocation.X + 420
		DrawShadowedString(hudFont, "PrinceOfPersia.net beta version: " & RetrieveLinkerTimestamp().ToShortDateString(), hudLocation, Color.White)


	End Sub

	Private Sub DrawShadowedString(font As SpriteFont, value As String, position As Vector2, color__1 As Color)
		If value Is Nothing Then
			value = "MAP_blockroom.xml"
		End If
		spriteBatch.DrawString(font, value, position + New Vector2(1F, 1F), Color.Black)
		spriteBatch.DrawString(font, value, position, color__1)
	End Sub




	Private Function RetrieveLinkerTimestamp() As DateTime
		Dim filePath As String = System.Reflection.Assembly.GetCallingAssembly().Location
		Const  c_PeHeaderOffset As Integer = 60
		Const  c_LinkerTimestampOffset As Integer = 8
		Dim b As Byte() = New Byte(2047) {}
		Dim s As System.IO.Stream = Nothing

		Try
			s = New System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read)
			s.Read(b, 0, 2048)
		Finally
			If s IsNot Nothing Then
				s.Close()
			End If
		End Try

		Dim i As Integer = System.BitConverter.ToInt32(b, c_PeHeaderOffset)
		Dim secondsSince1970 As Integer = System.BitConverter.ToInt32(b, i + c_LinkerTimestampOffset)
		Dim dt As New DateTime(1970, 1, 1, 0, 0, 0)
		dt = dt.AddSeconds(secondsSince1970)
		dt = dt.AddHours(TimeZone.CurrentTimeZone.GetUtcOffset(dt).Hours)
		Return dt
	End Function

End Class

